﻿using System;
using System.Web.Mvc;
using System.Web.Security;
using OpusSuite.Globalisation;
using OpusSuite.Models;
using OpusSuite.Utility;
using OpusSuite.ViewModels.AccountAdmin;
using OpusSuite.Models.Model.WebAdmin;
using System.Web;
using System.Web.UI;
using System.Data.Entity;
using System.Linq;

//using MvcMiniProfiler;

namespace OpusSuite.Controllers
{
    public class AccountAdminController : BaseController
    {
        [Attributes.AllowAnonymous]
        public ActionResult LogOn()
        {
            WebUtil.RemoveAuthCookie();

            if (System.IO.File.Exists(Request.MapPath("~/App_Data/setupneeded.txt")))
                return RedirectToAction("Setup", "AccountAdmin");

            return View();
        }

        [HttpPost]
        [Attributes.AllowAnonymous]
        public ActionResult LogOn(string userName, string password, string databaseName, string serverName, Enums.ServerTypes serverType, string returnUrl)
        {
            try
            {
                HttpCookie cookie = WebUtil.CookieFromLogin(userName, password, databaseName, serverName, serverType);
                //HttpContext.Current.Response.Cookies.Add(cookie);
                HttpContext.Response.Cookies.Add(cookie);

                if (!ValidateLogOn(userName, password, databaseName, serverName))
                {
                    return View();
                }

                var model = new OpusSuiteModel(WebUtil.ServerTypeFromCookie(), WebUtil.ConnectionStringFromCookie());
                User u = model.Context.Users.FirstOrDefault(x => x.UserName == userName);
                if (u!=null && u.ValidatePassword(password))
                {
                    model.SignInUser(userName, password, databaseName, serverName, Request.UserHostAddress);

                    FormsAuthentication.SetAuthCookie(userName, false);

                    if (!String.IsNullOrEmpty(returnUrl) && returnUrl != "/")
                    {
                        return Redirect(returnUrl);
                    }
                }
                else
                {
                    ModelState.AddModelError("login",
                                             UIResources.GetMessage(Enums.OpusSuiteResource.AccountAdmin,
                                                                    "CannotSignInUser",
                                                                    userName));
                    return View();
                }
            }
            catch (Exception e)
            {
                ModelState.AddModelError("login",
                                         UIResources.GetMessage(Enums.OpusSuiteResource.AccountAdmin,
                                                                "CannotSignInUser",
                                                                userName) + e.Message);
                return View();
            }

            return RedirectToAction("Index", "Home");
        }

        public ActionResult LogOff()
        {
            var model = new OpusSuiteModel(WebUtil.ServerTypeFromCookie(), WebUtil.ConnectionStringFromCookie());

            try
            {
                WebUtil.RemoveAuthCookie();
                FormsAuthentication.SignOut();
                model.SignOutUser(User.Identity.Name);
            }
            catch (Exception e)
            {
                ModelState.AddModelError("logoff", e.Message);
            }

            return RedirectToAction("Index", "Home");
        }

        private bool ValidateLogOn(string userName, string password, string databaseName, string serverName)
        {
            if (String.IsNullOrEmpty(userName))
            {
                ModelState.AddModelError("username", UIResources.GetMessage(Enums.OpusSuiteResource.AccountAdmin,
                                                                "UserNameRequired"));
            }
            if (String.IsNullOrEmpty(password))
            {
                ModelState.AddModelError("password", UIResources.GetMessage(Enums.OpusSuiteResource.AccountAdmin,
                                                                "PasswordRequired"));
            }
            if (String.IsNullOrEmpty(databaseName))
            {
                ModelState.AddModelError("databaseName", UIResources.GetMessage(Enums.OpusSuiteResource.AccountAdmin,
                                                                "DatabaseRequired"));
            }
            if (String.IsNullOrEmpty(serverName))
            {
                ModelState.AddModelError("serverName", UIResources.GetMessage(Enums.OpusSuiteResource.AccountAdmin,
                                                                "ServerRequired"));
            }

            return ModelState.IsValid;
        }

        [Attributes.AllowAnonymous]
        public ActionResult Setup()
        {
            WebUtil.RemoveAuthCookie();

            if (!System.IO.File.Exists(Request.MapPath("~/App_Data/setupneeded.txt")))
                return RedirectToAction("LogOn", "AccountAdmin");

            return View();
        }

        [HttpPost]
        [Attributes.AllowAnonymous]
        public ActionResult Setup(string userName, string password, string databaseName, string serverName, Enums.ServerTypes serverType, string adminUserName)
        {
            var model = new OpusSuiteModel(serverType, WebUtil.ConnectionStringFromLogin(userName, password, databaseName, serverName, serverType));
            try
            {
                model.SetupCreateDatabase(userName, password, databaseName, serverName, serverType, adminUserName);
                var s = Request.MapPath("~/App_Data/setupneeded.txt");
                if (System.IO.File.Exists(s))
                    System.IO.File.Delete(s);

                System.IO.File.Create(Request.MapPath("~/App_Data/firsttime.txt"));

                model.AddApplicationMessage(Enums.ApplicationMessageType.Message,
                    Enums.ApplicationMessageLevel.Information,
                    UIResources.GetMessage(Enums.OpusSuiteResource.AccountAdmin, "DatabaseCreatedSuccessfully"),
                    UIResources.GetMessage(Enums.OpusSuiteResource.AccountAdmin, "DatabaseCreatedSuccessfullyDetails"),
                    new User(), Enums.ApplicationMessageLifetime.Seconds, 5);

                model.SignInUser(adminUserName, adminUserName, databaseName, serverName, Request.UserHostAddress);

                FormsAuthentication.SetAuthCookie(adminUserName, false);

                return RedirectToAction("Index", "Home");
            }
            catch (Exception e)
            {
                ModelState.AddModelError("Error", UIResources.GetMessage(Enums.OpusSuiteResource.AccountAdmin,
                                                                "CannotCreateDatabase", e.Message));
            }

            return View();
        }

        public ActionResult UserProfile()
        {
            var model = new OpusSuiteModel(WebUtil.ServerTypeFromCookie(), WebUtil.ConnectionStringFromCookie());
            var viewModel = new UserProfileModel();

            try
            {
                //var profiler = MiniProfiler.Current; // it's ok if this is null

                //using (profiler.Step("Loading profile"))
                //{
                    User user = model.Context.Users
                        .Where(x => x.UserName == User.Identity.Name)
                        .Include(x => x.Profile)
                        .Include(y => y.Profile.Theme)
                        .Include(x => x.Profile.Country)
                        .FirstOrDefault();

                    if (user != null)
                    {
                        viewModel.UserName = user.UserName;
                        viewModel.DisplayName = user.Profile.DisplayName;
                        viewModel.ThemeId = user.Profile.Theme.Id;
                        viewModel.ThemeName = user.Profile.Theme.Name;
                        viewModel.CountryId = user.Profile.Country.Id;
                        viewModel.CountryDescription = user.Profile.Country.Description;
                        viewModel.Settings = user.Profile.Settings;
                    }
                //}

                //using (profiler.Step("Loading themes"))
                //{
                    ViewBag.Themes = model.Context.Themes;
                //}
            }
            catch (Exception e)
            {
                ModelState.AddModelError("Error", UIResources.GetMessage(Enums.OpusSuiteResource.AccountAdmin,
                                                                "CannotViewUserProfile", User.Identity.Name, e.Message));
            }

            ViewBag.Breadcrumbs = WebUtil.BuildBreadcrumbs("Home,User Profile");
            return View(viewModel);
        }

        [HttpPost]
        public ActionResult UserProfile(UserProfileModel userProfile)
        {
            var model = new OpusSuiteModel(WebUtil.ServerTypeFromCookie(), WebUtil.ConnectionStringFromCookie());

            try
            {
                User user = model.Context.Users.FirstOrDefault(x => x.UserName == userProfile.UserName);

                ViewBag.Themes = model.Context.Themes;

                if (System.IO.File.Exists(Server.MapPath("~/App_Data/firsttime.txt")))
                {
                    if (string.IsNullOrWhiteSpace(userProfile.CurrentPassword) || string.IsNullOrWhiteSpace(userProfile.NewPassword) || string.IsNullOrWhiteSpace(userProfile.ConfirmPassword))
                    {
                        model.AddApplicationMessage(Enums.ApplicationMessageType.Message,
                            Enums.ApplicationMessageLevel.Error,
                            UIResources.GetMessage(Enums.OpusSuiteResource.AccountAdmin, "MustChangePassword"),
                            UIResources.GetMessage(Enums.OpusSuiteResource.AccountAdmin, "MustChangePasswordFromDefault"),
                            user);

                        return View(userProfile);
                    }
                }

                var profile = new UserProfile
                {
                    Theme = model.Context.Themes.FirstOrDefault(x => x.Id == userProfile.ThemeId),
                    Country = model.Context.Countries.FirstOrDefault(x => x.Id == userProfile.CountryId)
                };

                model.Context.UserProfiles.Add(profile);
                model.Context.SaveChanges();
            }
            catch (Exception e)
            {
                ModelState.AddModelError("Error", UIResources.GetMessage(Enums.OpusSuiteResource.AccountAdmin, "CannotUpdateUserProfile", User.Identity.Name, e.Message));
            }

            return View(userProfile);
        }

        [Attributes.AllowAnonymous]
        public ActionResult Dashboard()
        {
            return View();
        }

        [HttpPost]
        [OutputCache(Location = OutputCacheLocation.None, NoStore = true, Duration = 0)]
        public JsonResult ChangePassword(string userName, string oldPassword, string newPassword, string confirmPassword)
        {
            bool ok = true;
            string message = "";
            string description = "";
            Enums.ApplicationMessageLevel level = Enums.ApplicationMessageLevel.Information;

            try
            {
                OpusSuiteModel model = new OpusSuiteModel(WebUtil.ServerTypeFromCookie(), WebUtil.ConnectionStringFromCookie());
                User u = model.Context.Users.FirstOrDefault(x => x.UserName == User.Identity.Name);

                if (u==null || string.IsNullOrWhiteSpace(userName) || string.IsNullOrWhiteSpace(oldPassword) || string.IsNullOrWhiteSpace(newPassword) || string.IsNullOrWhiteSpace(confirmPassword))
                {
                    message = string.Format("Validation failed changing password for {0}", userName);
                    description = string.Format("Validation failed changing password for {0}: {1}", userName, "Please make sure all required fields are present.");
                    level = Enums.ApplicationMessageLevel.Error;
                    ok = false;
                }
                else
                {
                    if (string.Compare(newPassword, confirmPassword, StringComparison.InvariantCulture) != 0)
                    {
                        message = string.Format("Validation failed changing password for {0}", userName);
                        description = string.Format("Validation failed changing password for {0}: {1}", userName, "Confirmation password does not match new password.");
                        level = Enums.ApplicationMessageLevel.Error;
                        ok = false;
                    }
                }

                try
                {
                    if (ok)
                    {
                        model.ChangePassword(u, oldPassword, newPassword);
                        message = string.Format("Password changed successfully.");
                        description = string.Format("Password changed successfully.");

                        // Log user out and in again
                        model.SignOutUser(User.Identity.Name);
                        WebUtil.RemoveAuthCookie();
                        FormsAuthentication.SignOut();

                        HttpCookie cookie = WebUtil.CookieFromLogin(u.UserName, newPassword, WebUtil.DatabaseNameFromCookie(), WebUtil.ServerNameFromCookie(), WebUtil.ServerTypeFromCookie());
                        HttpContext.Response.Cookies.Add(cookie);

                        model = new OpusSuiteModel(WebUtil.ServerTypeFromCookie(), WebUtil.ConnectionStringFromCookie());
                        model.SignInUser(u.UserName, newPassword, WebUtil.DatabaseNameFromCookie(), WebUtil.ServerNameFromCookie(), Request.UserHostAddress);
                        FormsAuthentication.SetAuthCookie(u.UserName, false);
                    }
                }
                catch (Exception e)
                {
                    message = string.Format("Validation failed changing password for {0}", userName);
                    description = string.Format("Validation failed changing password for {0}: {1}", userName, e.Message);
                    level = Enums.ApplicationMessageLevel.Error;
                    ok = false;
                }

                model.AddApplicationMessage(
                    Enums.ApplicationMessageType.Message,
                    level,
                    message,
                    description,
                    model.Context.Users.FirstOrDefault(x => x.UserName == User.Identity.Name));
            }
            catch
            {
                // we cant do anything as we are in an ajax request so the connection should
                // have been valid
                ok = false;
            }

            return Json(new { Success = ok });
        }

        public ActionResult FirstTime()
        {
            var model = new OpusSuiteModel(WebUtil.ServerTypeFromCookie(), WebUtil.ConnectionStringFromCookie());
            var viewModel = new UserProfileModel();

            try
            {
                //var profiler = MiniProfiler.Current; // it's ok if this is null

                //using (profiler.Step("Loading profile"))
                //{
                User user = model.Context.Users
                    .Where(x => x.UserName == User.Identity.Name)
                    .Include(x => x.Profile)
                    .Include(y => y.Profile.Theme)
                    .Include(x => x.Profile.Country)
                    .Include(x => x.Profile.Settings)
                    .FirstOrDefault();

                if (user != null)
                {
                    viewModel.UserName = user.UserName;
                    viewModel.DisplayName = user.Profile.DisplayName;
                    viewModel.ThemeId = user.Profile.Theme.Id;
                    viewModel.ThemeName = user.Profile.Theme.Name;
                    viewModel.CountryId = user.Profile.Country.Id;
                    viewModel.CountryDescription = user.Profile.Country.Description;
                    viewModel.Settings = user.Profile.Settings;
                }
                //}

                //using (profiler.Step("Loading themes"))
                //{
                ViewBag.Themes = model.Context.Themes;
                //}
            }
            catch (Exception e)
            {
                ModelState.AddModelError("Error", UIResources.GetMessage(Enums.OpusSuiteResource.AccountAdmin, "CannotViewUserProfile", User.Identity.Name, e.Message));
            }

            ViewBag.Breadcrumbs = WebUtil.BuildBreadcrumbs("Home,User Profile");
            return View(viewModel);
        }

        [HttpPost]
        public JsonResult FirstTime(UserProfileModel profileModel)
        {
            var model = new OpusSuiteModel(WebUtil.ServerTypeFromCookie(), WebUtil.ConnectionStringFromCookie());

            try
            {
                User user = model.Context.Users.FirstOrDefault(x => x.UserName == profileModel.UserName);
                if (user != null)
                {
                    ViewBag.Themes = model.Context.Themes;

                    if (string.IsNullOrWhiteSpace(profileModel.CurrentPassword) ||
                        string.IsNullOrWhiteSpace(profileModel.NewPassword) ||
                        string.IsNullOrWhiteSpace(profileModel.ConfirmPassword))
                    {
                        model.AddApplicationMessage(Enums.ApplicationMessageType.Message,
                                                    Enums.ApplicationMessageLevel.Error,
                                                    UIResources.GetMessage(Enums.OpusSuiteResource.AccountAdmin, "MustChangePassword"),
                                                    UIResources.GetMessage(Enums.OpusSuiteResource.AccountAdmin, "MustChangePasswordFromDefault"),
                                                    user);
                        return Json(false);
                    }

                    if (string.Compare(profileModel.NewPassword, profileModel.ConfirmPassword, StringComparison.CurrentCulture) != 0)
                    {
                        model.AddApplicationMessage(Enums.ApplicationMessageType.Message,
                                                    Enums.ApplicationMessageLevel.Error,
                                                    UIResources.GetMessage(Enums.OpusSuiteResource.AccountAdmin, "MustChangePassword"),
                                                    UIResources.GetMessage(Enums.OpusSuiteResource.AccountAdmin, "MustChangePasswordMustMatch"),
                                                    user);
                        return Json(false);                        
                    }

                    if (string.Compare(user.UserName, profileModel.NewPassword, StringComparison.CurrentCulture)==0 || string.Compare(profileModel.CurrentPassword, profileModel.NewPassword, StringComparison.CurrentCulture)==0)
                    {
                        model.AddApplicationMessage(Enums.ApplicationMessageType.Message,
                                                    Enums.ApplicationMessageLevel.Error,
                                                    UIResources.GetMessage(Enums.OpusSuiteResource.AccountAdmin, "MustChangePassword"),
                                                    UIResources.GetMessage(Enums.OpusSuiteResource.AccountAdmin, "MustChangePasswordMustNotMatchOld"),
                                                    user);
                        return Json(false);                                                                        
                    }

                    if (!user.ValidatePassword(profileModel.CurrentPassword))
                    {
                        model.AddApplicationMessage(Enums.ApplicationMessageType.Message,
                                                    Enums.ApplicationMessageLevel.Error,
                                                    UIResources.GetMessage(Enums.OpusSuiteResource.AccountAdmin, "MustChangePassword"),
                                                    UIResources.GetMessage(Enums.OpusSuiteResource.AccountAdmin, "MustChangePasswordOldPasswordIncorrect"),
                                                    user);
                        return Json(false);                                                
                    }

                    model.ChangePassword(user, profileModel.CurrentPassword, profileModel.NewPassword);
                    
                    // Log user out and in again
                    model.SignOutUser(User.Identity.Name);
                    WebUtil.RemoveAuthCookie();
                    FormsAuthentication.SignOut();

                    HttpCookie cookie = WebUtil.CookieFromLogin(user.UserName, profileModel.NewPassword, WebUtil.DatabaseNameFromCookie(), WebUtil.ServerNameFromCookie(), WebUtil.ServerTypeFromCookie());
                    HttpContext.Response.Cookies.Add(cookie);

                    model = new OpusSuiteModel(WebUtil.ServerTypeFromCookie(), WebUtil.ConnectionStringFromCookie());
                    model.SignInUser(user.UserName, profileModel.NewPassword, WebUtil.DatabaseNameFromCookie(), WebUtil.ServerNameFromCookie(), Request.UserHostAddress);
                    FormsAuthentication.SetAuthCookie(user.UserName, false);

                    // Setup profile
                    var profile = user.Profile;

                    profile.DisplayName = profileModel.DisplayName;
                    profile.Theme = model.Context.Themes.FirstOrDefault(x => x.Id == profileModel.ThemeId);
                    profile.Country = model.Context.Countries.FirstOrDefault(x => x.Id == profileModel.CountryId);

                    model.Context.SaveChanges();

                    if (System.IO.File.Exists(Server.MapPath("~/App_Data/firsttime.txt")))
                    {
                        System.IO.File.Delete(Server.MapPath("~/App_Data/firsttime.txt"));
                    }

                    return Json(true);
                }
                else
                {
                    model.AddApplicationMessage(Enums.ApplicationMessageType.Message,
                                                Enums.ApplicationMessageLevel.Error,
                                                UIResources.GetMessage(Enums.OpusSuiteResource.AccountAdmin, "CannotUpdateProfile"),
                                                UIResources.GetMessage(Enums.OpusSuiteResource.AccountAdmin, "CannotUpdateProfileDetails", User.Identity.Name),
                                                null);                    
                }
            }
            catch (Exception e)
            {
                            model.AddApplicationMessage(Enums.ApplicationMessageType.Message,
                                                        Enums.ApplicationMessageLevel.Error,
                                                        UIResources.GetMessage(Enums.OpusSuiteResource.AccountAdmin, "CannotUpdateProfile"),
                                                        UIResources.GetMessage(Enums.OpusSuiteResource.AccountAdmin, "CannotUpdateProfileDetailsWithError", User.Identity.Name, e.Message),
                                                        null);
            }

            return Json(false);
        }
    }
}
